using System;
using System.ComponentModel;

using Supremacy.Annotations;
using Supremacy.Collections;
using Supremacy.Diplomacy;
using Supremacy.Entities;
using Supremacy.Game;

namespace Supremacy.Client.Views
{
    public interface IEmpirePlayerStatusCollection : IIndexedCollection<EmpirePlayerStatus>
    {
        void Update([NotNull] ILobbyData lobbyData);
        void UpdatePlayerReadiness([NotNull] IPlayer player);
        void ClearPlayerReadiness();
        void UpdateRelationshipStatus();
    }

    internal class EmpirePlayerStatusCollection : KeyedCollectionBase<Civilization, EmpirePlayerStatus>, IEmpirePlayerStatusCollection
    {
        public EmpirePlayerStatusCollection()
            : base(o => o.Empire) {}

        public void Update([NotNull] ILobbyData lobbyData)
        {
            if (lobbyData == null)
                throw new ArgumentNullException("lobbyData");

            foreach (var player in lobbyData.Players)
                this[player.Empire].Player = player;

            UpdateRelationshipStatus();
        }

        public void UpdatePlayerReadiness([NotNull] IPlayer player)
        {
            if (player == null)
                throw new ArgumentNullException("player");

            this[player.Empire].IsReady = true;
        }

        public void ClearPlayerReadiness()
        {
            foreach (var status in this)
                status.IsReady = false;
        }

        public void UpdateRelationshipStatus()
        {
            this.ForEach(o => o.UpdateRelationshipStatus());
        }
    }

    public class EmpirePlayerStatus : INotifyPropertyChanged
    {
        private readonly IClientContext _clientContext;
        private readonly int _empireId;
        private int _playerId = Game.Player.ComputerPlayerID;

        public EmpirePlayerStatus([NotNull] IClientContext clientContext, [NotNull] Civilization empire)
        {
            if (clientContext == null)
                throw new ArgumentNullException("clientContext");
            if (empire == null)
                throw new ArgumentNullException("empire");
            if (!empire.IsEmpire)
                throw new ArgumentException(@"Civilization must be an empire.", "empire");

            _clientContext = clientContext;
            _empireId = empire.CivID;
        }

        #region Empire Property
        public Civilization Empire
        {
            get { return _clientContext.CurrentGame.Civilizations[_empireId]; }
        }
        #endregion

        #region Player Property
        public IPlayer Player
        {
            get
            {
                if (_playerId < Game.Player.GameHostID)
                {
                    return new Player
                           {
                               EmpireID = _empireId,
                               PlayerID = Game.Player.ComputerPlayerID
                           };
                }

                return _clientContext.Players[_playerId];
            }
            set
            {
                if (value == null)
                    _playerId = Game.Player.UnassignedPlayerID;
                else
                    _playerId = value.PlayerID;

                this.OnPropertyChanged("Player");

                if (!this.Player.IsHumanPlayer)
                    this.IsReady = true;

                this.UpdateRelationshipStatus();
            }
        }
        #endregion

        #region IsReady Property
        private bool _isReady;

        public bool IsReady
        {
            get { return this.Player.IsHumanPlayer ? _isReady : true; }
            set
            {
                _isReady = value;

                this.OnPropertyChanged("IsReady");
            }
        }
        #endregion

        #region RelationshipStatus Property

        private RelationshipStatus _relationshipStatus;

        public RelationshipStatus RelationshipStatus
        {
            get { return _relationshipStatus; }
            set
            {
                if (value == _relationshipStatus)
                    return;

                _relationshipStatus = value;

                this.OnPropertyChanged("RelationshipStatus");
            }
        }

        #endregion

        public void UpdateRelationshipStatus()
        {
            var localPlayerEmpireId = _clientContext.LocalPlayer.EmpireID;

            if (_empireId == localPlayerEmpireId)
            {
                this.RelationshipStatus = RelationshipStatus.Self;
                return;
            }

            this.RelationshipStatus = _clientContext.CurrentGame.Relationships[localPlayerEmpireId, _empireId].Status;
        }

        #region Implementation of INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}